# _*_ coding: utf-8 _*_
#!/usr/bin/env python

#      ___________________
#  ___| Modulbeschreibung \_________________________________________________________________________
# | Die Spiellogik interpoliert die Bewegungsdaten und bietet die Möglichkeit das Fahrzeug zu steuern.
# | Ausserdem ist sie für die Kollisionsabfrage und verknüpfung des Netzwerkes mit der Grafik verantwortlich
# |__________________________________________________________________| Zuständigkeit [Jannik |____


import sys, os
import pygame
import threading
import time
import math

class GameLogic(threading.Thread):
	'''Kuemmert sich um den Spielablauf wie Interpolation und Steuerung'''
	
	def __init__(self, race):
		'''Konstruktor'''
		
		threading.Thread.__init__(self)
		self.race			= race
		#self.stop_thread	= threading.Event()
		self.run_thread		= True #threading.Event()
		#self.run_thread.set()
		self.stoped			= threading.Event()
		#print self.stop_thread, self.stoped
		self.controll_keys	= {	'key_up':		False,
								'key_down':		False,
								'key_left':		False,
								'key_right':	False}
		self.rounds			= 1
		self.next_checkpoint	= 1
		
		self.surface = [#Die verschiedenen Werte fuer Beschleunigung auf unterschiedlichem Untergrund
						#1 Normaler Untergrund
						[[1.5,0.006],		#Beschleunigen
						[-0.5,0.008],	#Bremsen bzw. Rï¿½ckwaerts fahren
						[0,0.005]],		#Ausrollen
						
						#2 Schlecht befahrbarer Untergrund
						[[0.25,0.01],		#Beschleunigen
						[-0.25,0.03],	#Bremsen bzw. Rï¿½ckwaerts fahren
						[0,0.03]],		#Ausrollen
						#3 Boost
						[1,2]]

		self.speed = 0 #Die aktuelle Geschwindigkeit		
		self.on_street = 0 #Befindet sich das Auto abseits der Strasse so ist dieser Wert 1
		self.rot_speed = 0	#Rotationsgeschwindigkeit
		self.finish = False #True wenn durchs Ziel gefahren wurde
		
		#Fuer das Netzwerk
		self.needSync = 100 #Gibt an nach wievielen Frames die Positionsdaten Synchronisiert werden sollen
		
		#Tasten welche von den einzelnen Spielern aktuell gedrueckt werden
		self.keys_pressed = []
		self.keystosend = {} # Hier kommen die Tasten rein, welche sich veraendert haben um sie anschliessend uebers Netzwer zu versenden
		
		#Um eine Konstante Framerate innerhalb der GameLogic zu haben
		self.clock = pygame.time.Clock()
		
	def run(self):
		'''Die Schleife in welcher die Spiellogik lauft'''
		
		rot_speed = 0.00
		
		#Hier wird eine Liste mit allen Tastendruecken fuer jeden Spieler erstellt
		for player in self.race.players:
			self.keys_pressed.append([False,False,False,False]) #Up,Down,Left,Right
		
		#Das eigene kart
		self.kart = self.race.players[self.race.network.getPlayernumber()]
		
		self.race.sound.playMusic("startrace", loop = 0)
		####################################
		####################################
		##Anzeigen eines Countdowns!########
		####################################
		####################################
		time.sleep(3)
		
		
		#Wird auf False gesetzt wenn der Thread beendet werden soll
		self.race.sound.playMusic("mariocircuit")
		while self.run_thread: #not self.stop_thread.isSet():

			self.checkCheckpoint()
			self.checkControl()
			
			#Hier wird überprüft ob das Ziel erreicht ist
			if self.rounds > 3:
				print "FINISH!!!!!!!"
				self.finish == True
				self.race.network.sendFinish()
				self.race.sound.playMusic("endrace")
				
				##Kann auch ausserhalb der while Schleife laufen
				while self.finish:
					##Andere Spieler ausgeben, evtl. Platzierungen anzeigen
					##self.race.network.Client.positions ist ein Array mit den Spielerpositionen in der Reihenfolge 1,2,3 None wenn noch keiner feststeht
					self.__calculateAnimation()
					self.__showHighScore()
					
					#Überprüfen ob alle ins Ziel gefahren sind
					counter = 0
					endcounter = 0
					playercounter = 0
					while counter < 8:
						if self.race.network.Client.positions != None:
							endcounter+=1
						if self.race.network.Client.playerinf != None:
							playercounter+=1
						
						#Wenn dem So ist Platzierungen anzeigen und dann Spiel beenden
						if playercounter == endcounter:
							print self.race.network.Client.positions
							break
				break			
				
			self.__calculateAnimation()
	
			#Alle paar Frames muss ein kompletter Sync erfolgen, damit die Sprites an der richtigen Stelle angezeigt werden
			self.needSync -= 1
			if self.needSync <= 0:
				if self.race.network.syncData() == False:
					##Alles andere Stoppen
					break
				self.needSync = 100
				
			


				
			#Hier wird ueberprueft welche Tastendruecke sich veraendert haben

			
			if len(self.keystosend) > 0:

				self.keystosend['number'] = self.race.network.getPlayernumber()
				#Hier werden die Tastendruecke an die Anderen Mitspieler versendet
				if self.race.network.sendKeys(self.keystosend) == False:
					##Alles Stoppen
					break
				
				#Da die Tasten nichtmehr versendet werden muessen wird das Dictionary wieder geleert
				self.keystosend.clear()
							
			#Wird benoetigt damit das kart auf unterschiedlich schnellen rechnern gleichschnell faehrt
			self.clock.tick(50)


		self.stoped.set()
	
	def __showHighScore(self):
		for playernum in self.race.network.Client.positions:
			pass
	
	def stopThread(self):
		self.run_thread = False
	
	def checkControl(self):
		'''Hier werden alle Tastendruecke abgefragt'''
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				self.race.stopRace()
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_ESCAPE:
					self.race.stopRace()
				if event.key == pygame.K_UP:
					#self.controll_keys['key_up']	= True
					self.keys_pressed[self.race.network.getPlayernumber()][0] = True
					self.keystosend['key_up'] = True
				elif event.key == pygame.K_DOWN:
					#self.controll_keys['key_down']	= True
					self.keys_pressed[self.race.network.getPlayernumber()][1] = True
					self.keystosend['key_down'] = True
				if event.key == pygame.K_LEFT:
					#self.controll_keys['key_left']	= True
					self.keys_pressed[self.race.network.getPlayernumber()][2] = True
					self.keystosend['key_left'] = True
				elif event.key == pygame.K_RIGHT:
					#self.controll_keys['key_right']	= True
					self.keys_pressed[self.race.network.getPlayernumber()][3] = True
					self.keystosend['key_right'] = True
			
			elif event.type == pygame.KEYUP:
				if event.key == pygame.K_UP:
					#self.controll_keys['key_up']	= False
					self.keys_pressed[self.race.network.getPlayernumber()][0] = False
					self.keystosend['key_up'] = False
				elif event.key == pygame.K_DOWN:
					#self.controll_keys['key_down']	= False
					self.keys_pressed[self.race.network.getPlayernumber()][1] = False
					self.keystosend['key_down'] = False
				if event.key == pygame.K_LEFT:
					#self.controll_keys['key_left']	= False
					self.keys_pressed[self.race.network.getPlayernumber()][2] = False
					self.keystosend['key_left'] = False
				elif event.key == pygame.K_RIGHT:
					#self.controll_keys['key_right']	= False
					self.keys_pressed[self.race.network.getPlayernumber()][3] = False
					self.keystosend['key_right'] = False
	
	def __checkCollision(self, player, tile):
		'''Liefert True zurueck wenn sich der Wagen auf einem nicht befahrbaren Tile befindet'''
		if tile > 721 and tile < 800:
			return True		
		#if tile > self.race.game_map.tilemap_size[0] * self.race.game_map.tile_size[1] / 2 and tile < 1292:
		#	print tile
			return True
		return False

	def __calculateAnimation(self):
		#Updaten der Positionsdaten der einzelnen Spieler!

		for player in range(8):
			
			self.race.lock.acquire()
			#Hier wird das Tile ermittelt auf welchem sich das Fahrzeug aktuell befindet
			tile = self.race.game_map.tilemap[int(self.race.players[player].y_pos / self.race.game_map.tile_size[0])][int(self.race.players[player].x_pos / self.race.game_map.tile_size[1])]
		
			
			#Abfrage: Ist der Wagen auf der Strasse?
			#if self.tile % self.race.game_map.tileset_size[0] < self.race.game_map.tileset_size[0] / 2 and self.tile < (self.race.game_map.tileset_size[1] / 2) * self.race.game_map.tileset_size[0]:
			if tile % self.race.game_map.tileset_size[0] < self.race.game_map.tileset_size[0] / 2 and tile < (self.race.game_map.tileset_size[1] / 2) * self.race.game_map.tileset_size[0] or tile > 1335:
				on_street = 0
			else: on_street = 1
			
			#Dieser Teil ist fuer die Lenkung der Fahrzeuge zusateandig				
			if self.keys_pressed[player][2] and self.race.players[player].rot_speed > -0.011:
				self.race.players[player].rot_speed -=  0.001
		
			elif self.keys_pressed[player][3] and self.race.players[player].rot_speed < 0.011:
				self.race.players[player].rot_speed +=  0.001
			
			else:
				if self.race.players[player].rot_speed > 0.001:
					self.race.players[player].rot_speed -=  0.002
				elif self.race.players[player].rot_speed < -0.001:
					self.race.players[player].rot_speed +=  0.002
				else: self.race.players[player].rot_speed = 0

			#self.race.players[player].angle += 0.009
			
			
			self.race.players[player].angle += self.race.players[player].rot_speed

			#Winkel ueberpruefen und ggf. anpassen
			if self.race.players[player].angle < 0:
				self.race.players[player].angle = math.pi * 2 - self.race.players[player].rot_speed
		
			elif self.race.players[player].angle > math.pi * 2:
				self.race.players[player].angle = self.race.players[player].rot_speed
					
			#Geschwindigkeitsberechnung wenn die Taste zum Beschleunigen gedrueckt wird
			if self.keys_pressed[player][0]and self.race.players[player].speed < 1.499:
				self.race.players[player].speed += self.surface[on_street][0][1]*(self.surface[on_street][0][0]-self.race.players[player].speed)

			#Geschwindigkeitsberechnung wenn die Taste zum Bremsen gedrueckt wird
			elif self.keys_pressed[player][1]:
				self.race.players[player].speed += self.surface[on_street][1][1]*(self.surface[on_street][1][0]-self.race.players[player].speed)
				
			#Geschwindigkeitsberechnung wenn keine Taste gedrueckt wird
			elif self.race.players[player].speed > 0.001:
				self.race.players[player].speed += self.surface[on_street][2][1]*(self.surface[on_street][2][0]-self.race.players[player].speed)
			else:
				self.race.players[player].speed = 0
					
			self.race.players[player].x_pos		+= math.cos(self.race.players[player].angle) * self.race.players[player].speed
			self.race.players[player].y_pos		+= math.sin(self.race.players[player].angle) * self.race.players[player].speed	
			
			#Hier wird auf Kollisionen mit der Bande geprueft
			if self.__checkCollision(player, tile):
				if player == self.race.network.getPlayernumber(): self.race.sound.playSound("crash")
				self.race.players[player].x_pos		-= math.cos(self.race.players[player].angle) * self.race.players[player].speed*4
				self.race.players[player].y_pos		-= math.sin(self.race.players[player].angle) * self.race.players[player].speed*4 
				self.race.players[player].speed 	= -self.race.players[player].speed/3
				
			
			self.race.lock.release()	
				
	def checkCheckpoint(self):
		checkpoint	= self.race.game_map.checkpoints[self.next_checkpoint]
		# Weil sich das Kart sonst nicht mit mehr als 1px pro Update bewegen darf, wenn das Rechteck nur 1px hoch ist
		tolarance	= 2
		# Befindet sich das Kart in der "Box" um die Checkpointgerade?
		if (checkpoint[0][0] - tolarance < self.kart.x_pos / self.race.game_map.tile_size[0] < checkpoint[1][0] + tolarance
			and checkpoint[0][1] - tolarance < self.kart.y_pos / self.race.game_map.tile_size[0] < checkpoint[1][1] + 0):	#//!!!
			if self.next_checkpoint == 0:
				self.rounds += 1
			self.next_checkpoint += 1
			if self.next_checkpoint == len(self.race.game_map.checkpoints):
				self.next_checkpoint = 0
		

			